/******************************************************************************
 * @file     main.c
 * @brief    Demonstrate how to implement a USB dual virtual com port device.
 * @version  2.0.0
 * @date     17, Dec, 2014
 *
 * @note
 * Copyright (C) 2014 Nuvoton Technology Corp. All rights reserved.
 ******************************************************************************/
#include <stdio.h>
#include <string.h>
#include "Nano100Series.h"
#include "common.h"
#include "Config.h"
#include "proximity_sensor.h"
#include "UsbTransfer.h"
#include "Input.h"
#include "EventQueue.h"
#include "Timer1.h"
#include "hdmi_regset.h"
#include "audio.h"

uint8_t status_3d=MODE_2D;
uint8_t status_3d_to_set=MODE_2D;
uint8_t is_video_on = 0;
uint8_t is_unlock = 0;

/*---------------------------------------------------------------------------------------------------------*/
void SYS_Init(void)
{
	SYS_UnlockReg();

	CLK_EnableXtalRC(CLK_PWRCTL_HXT_EN_Msk);
	CLK_EnablePLL(CLK_PLLCTL_PLL_SRC_HXT, 96000000);
	CLK_WaitClockReady(CLK_CLKSTATUS_HXT_STB_Msk | CLK_CLKSTATUS_PLL_STB_Msk);
	CLK_SetHCLK(CLK_CLKSEL0_HCLK_S_PLL, CLK_HCLK_CLK_DIVIDER(3));
	SystemCoreClockUpdate();

	/* UART 0 */
	CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART_S_HXT, CLK_UART_CLK_DIVIDER(1));
	CLK_EnableModuleClock(UART0_MODULE);
	SYS->PB_L_MFP &= ~(SYS_PB_L_MFP_PB0_MFP_Msk | SYS_PB_L_MFP_PB1_MFP_Msk);
	SYS->PB_L_MFP |= (SYS_PB_L_MFP_PB0_MFP_UART0_RX | SYS_PB_L_MFP_PB1_MFP_UART0_TX);

	/* I2C0 */
	CLK_SetModuleClock(I2C0_MODULE, 0, 0);
	CLK_EnableModuleClock(I2C0_MODULE);
	SYS->PA_L_MFP &= ~(SYS_PA_L_MFP_PA5_MFP_Msk | SYS_PA_L_MFP_PA4_MFP_Msk);
	SYS->PA_L_MFP |= (SYS_PA_L_MFP_PA5_MFP_I2C0_SCL | SYS_PA_L_MFP_PA4_MFP_I2C0_SDA);

	/* I2C1 */
	CLK_SetModuleClock(I2C1_MODULE, 0, 0);
	CLK_EnableModuleClock(I2C1_MODULE);
	SYS->PA_H_MFP &= ~(SYS_PA_H_MFP_PA11_MFP_Msk | SYS_PA_H_MFP_PA10_MFP_Msk);
	SYS->PA_H_MFP |= (SYS_PA_H_MFP_PA11_MFP_I2C1_SCL | SYS_PA_H_MFP_PA10_MFP_I2C1_SDA);

	/* SPI1 */
	CLK_SetModuleClock(SPI1_MODULE, CLK_CLKSEL2_SPI1_S_HCLK, 0);
	CLK_EnableModuleClock(SPI1_MODULE);
	SYS->PC_H_MFP &= ~(SYS_PC_H_MFP_PC10_MFP_Msk | SYS_PC_H_MFP_PC11_MFP_Msk | SYS_PC_H_MFP_PC9_MFP_Msk);
	SYS->PC_H_MFP |= (SYS_PC_H_MFP_PC10_MFP_SPI1_MISO0 | SYS_PC_H_MFP_PC11_MFP_SPI1_MOSI0| SYS_PC_H_MFP_PC9_MFP_SPI1_SCLK);
	SYS->PC_H_MFP &= ~SYS_PC_H_MFP_PC8_MFP_Msk;
	SYS->PC_H_MFP |= SYS_PC_H_MFP_PC8_MFP_SPI1_SS0;
	SYS->PB_H_MFP &= ~SYS_PB_H_MFP_PB9_MFP_Msk;
	SYS->PB_H_MFP |= SYS_PB_H_MFP_PB9_MFP_SPI1_SS1;

	/* TIMER1 for motion sensor and proximity sensor */
	CLK_EnableModuleClock(TMR1_MODULE);
	CLK_SetModuleClock(TMR1_MODULE, CLK_CLKSEL1_TMR1_S_HXT, 0);

	/* USB */
	CLK_SetModuleClock(USBD_MODULE, 0, CLK_USB_CLK_DIVIDER(2));
	CLK_EnableModuleClock(USBD_MODULE);
	/* PWM */
  	//CLK_EnableModuleClock(PWM1_CH23_MODULE);
	//CLK_SetModuleClock(PWM1_CH23_MODULE, CLK_CLKSEL2_PWM1_CH23_S_HXT,0);
	//SYS->PC_H_MFP =(SYS->PC_H_MFP & ~ SYS_PC_H_MFP_PC15_MFP_Msk) | SYS_PC_H_MFP_PC15_MFP_PWM1_CH2;
	
//	CLK_EnableModuleClock(PWM0_CH01_MODULE);
//	CLK_SetModuleClock(PWM0_CH01_MODULE, CLK_CLKSEL1_PWM0_CH01_S_HXT,0);
//	SYS->PA_H_MFP =(SYS->PA_H_MFP & ~ SYS_PA_H_MFP_PA13_MFP_Msk) | SYS_PA_H_MFP_PA13_MFP_PWM0_CH1;
//	/*ADC */
//	 CLK_EnableModuleClock(ADC_MODULE);
//	 CLK_SetModuleClock(ADC_MODULE,CLK_CLKSEL1_ADC_S_HXT,CLK_ADC_CLK_DIVIDER(5));
//	 SYS->PA_L_MFP &= ~SYS_PA_L_MFP_PA0_MFP_Msk;
//	 SYS->PA_L_MFP |= SYS_PA_L_MFP_PA0_MFP_ADC_CH0;
//	 
//	 PA->OFFD = PA->OFFD |((1 << 0) << GP_OFFD_OFFD_Pos);
   
	/* Audio Amp */
	GPIO_SetMode(PA, BIT14, GPIO_PMD_OUTPUT);

	SYS_LockReg();
}

void key_init()
{
    GPIO_SetMode(PC, BIT0, GPIO_PMD_INPUT);
    GPIO_ENABLE_PULL_UP(PC, BIT0);

    GPIO_SetMode(PE, BIT5, GPIO_PMD_INPUT);
    GPIO_ENABLE_PULL_UP(PE, BIT5);
}

void EdidInit(void)
{
	int i;
	uint8_t sum;
	uint8_t tmp;

	sum = 0;
	for (i = 0; i < 127; i++) {
		tmp =  edid_3840[i + 2];
		sum += tmp;
	}
	edid_3840[i + 2] = -sum;

	sum = 0;
	for (i = 128; i < 255; i++) {
		sum += edid_3840[i + 2];                          
		
	}
	edid_3840[i + 2] = -sum;

	sum = 0;
	for (i = 0; i < 127; i++) {
		sum += edid_1080[i + 2];
	}
	edid_1080[i + 2] = -sum;

	sum = 0;
	for (i = 128; i < 255; i++) {
		sum += edid_1080[i + 2];
	}
	edid_1080[i + 2] = -sum;
}


int32_t main (void)
{
	int key_bright_count = 0;
	int key_3d_count = 0;
	int count_delay=0;
	int bright_delta = 6;
	enum proximity_sensor_state state;
	int lum_test_index = 0;
	
    SYS_Init();
	UART_Open(UART0, 115200);
	info("\nHighglass HMD power on ...\n");
	
	hdmi_audio_disable();
	
	HgConfigInit();
	EdidInit();

	EventQueueInit(&hmd_event_queue, &(hmd_events[0]), HMD_EVENT_SIZE);
	UsbTransferInit();

	GPIO_SetMode(PB, BIT14, GPIO_PMD_OUTPUT);
	GPIO_SetMode(PB, BIT13, GPIO_PMD_OUTPUT);
	GPIO_SetMode(PA, BIT9, GPIO_PMD_OUTPUT);
	GPIO_SetMode(PA, BIT14, GPIO_PMD_OUTPUT);
	GPIO_SetMode(PC, BIT6, GPIO_PMD_OUTPUT);

	GPIO_SetMode(PB, BIT2, GPIO_PMD_OUTPUT);
	GPIO_SetMode(PB, BIT6, GPIO_PMD_OUTPUT);

	sensor_init();

	proximity_sensor_init();

	SPI_init();
	CLK_SysTickDelay(3000);
//	PD14=0;
//	PD13=1;
	PB2=1;
	PB14=1;	
	PA9=0;	
	PB13=0;//oled 10v
	CLK_SysTickDelay(300);	
	PA9=1;
	PC6=1;
	CLK_SysTickDelay(300);
	PC6=0;	//hdmi reset	
	LVDS_i2c_init();
	PA14=0;
	
	i2c_init();
	//init_hdmi2mipi();

//	is_video_on = 0;
//	HDMI_init();
//	is_video_on = 1;
	key_init();

	USBD_Start();
	Timer1Open();
//	motor_init();
  audio_init();
	while(1) {
		//update_motor_speed();
		// handle USB event
		UsbTransferHandleEvent();

		// update sensor
		if (Timer1IsTrigger()) {
			Timer1ResetFlag();
			UsbTransferHandleSensorUpdate();
		}

#ifdef HMD_XY
		if (is_unlock) {
#endif
			// proximity check
			if(count_delay++>20) {
				state = proximity_sensor_get_state();
				if (state == PROXIMITY_SENSOR_STATE_CLOSE) {
					struct contrast tContrast;
					tContrast.w = 0;
					tContrast.r = tHgConfig.tContrast.r;
					tContrast.g = tHgConfig.tContrast.g;
					tContrast.b = tHgConfig.tContrast.b;
					//info("PROXIMITY_SENSOR_STATE_CLOSE\n");
					//info("NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN\n");
					count_delay=0;
					if (is_video_on == 0) {
						hdmi_video_start();
						//CLK_SysTickDelay(10000);
						SetContrast(&tContrast);
						oled_start();
						for (; tContrast.w <=tHgConfig.tContrast.w; tContrast.w++) {
							SetContrast(&tContrast);
							CLK_SysTickDelay(3 * 1000);
						}
						is_video_on = 1;
					}
				} else {	
					//info("PROXIMITY_SENSOR_STATE_LEAVE\n");
					//info("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\n");
					if (is_video_on &&count_delay>1500) {
						struct contrast tContrast;
						tContrast.w = tHgConfig.tContrast.w;
						tContrast.r = tHgConfig.tContrast.r;
						tContrast.g = tHgConfig.tContrast.g;
						tContrast.b = tHgConfig.tContrast.b;
						is_video_on = 0;
						for (; tContrast.w > 0; tContrast.w--) {
							SetContrast(&tContrast);
							CLK_SysTickDelay(1 * 1000);
						}
						oled_stop();
						hdmi_video_stop();
					}
				}
			}

			if (is_video_on) {
				// 3d mode key check
				if (PE5 == 0) {
					CLK_SysTickDelay(1000);
					if (PE5 == 0) {
            if (key_3d_count >= 10) {							
							 if (status_3d == MODE_2D)
								 status_3d = MODE_3D_FULL;
							 else if (status_3d == MODE_3D_FULL)
						     status_3d = MODE_2D;
							 Switch_3D(status_3d);
					  }
						else{
							key_3d_count++;
						}
					}
				} else {
					key_3d_count = 0;
				}
				
				// brightness key check
	/*			if (PC0 == 0) {
					// debounce
					CLK_SysTickDelay(1000);
					if (PC0 == 0) {
						if (key_bright_count >= 10) {
							tHgConfig.tBrightness.w += 15;
							if (bright_delta > 0) {
								InputReportKeyAuto(&hmd_event_queue, KEY_BRIGHTNESSUP);
							} else {
								InputReportKeyAuto(&hmd_event_queue, KEY_BRIGHTNESSDOWN);
							}
							
							if (tHgConfig.tBrightness.w >= BRIGHTNESS_MAX) {
								tHgConfig.tBrightness.w = BRIGHTNESS_MAX;
							} 
							SetBrightness(&tHgConfig.tBrightness);
							HgConfigWrite(&tHgConfig);
							key_bright_count = -10000000;
							info("on key bright, tHgConfig.tBrightness.w : %u\n",
								tHgConfig.tBrightness.w);
						} else {
							key_bright_count++;
						}
					}
				} else {
					key_bright_count = 0;
				}*/
			}

			// hdmi plug in and out check
			hdmi_monitor();
#ifdef HMD_XY
		}
#endif
	}
}



/*** (C) COPYRIGHT 2013 Nuvoton Technology Corp. ***/

